package c2.cross.business.championrace.handler;

import c2.cross.business.championrace.ChampionRaceModule;
import cate.game.pvp.championrace.data.ChampionRaceOpponent;
import cate.game.pvp.championrace.data.ChampionRacePs;
import cate.game.pvp.championrace.data.ChampionRaceRecord;
import cate.game.pvp.championrace.data.ChampionRaceSpec;
import cate.game.pvp.championrace.timer.ChampionRaceTimerTask;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

import static cate.game.event.championrace.ChampionRaceTimerEvent.EventType.*;

@Slf4j
public class ChampionRaceGroupSettingHandler extends AbstractChampionRaceSettingHandler{
    public ChampionRaceGroupSettingHandler(ChampionRaceModule parent) {
        super(parent);
    }

    @Override
    public boolean runSettingFunction(ChampionRaceTimerTask.Setting setting) {
        if (!parent.canChangeSpec(setting, setting.getEventType().getFlag())) {
            return true;
        }
        switch (setting.getEventType()) {
            case TRIAL_GROUP:
                runTrialGroupWith(setting);
                break;
            case KO_GROUP:
                runKoGroupWith(setting);
                break;
            case FINAL_GROUP:
                runFinalGroupWith(setting);
                break;
            default:
                break;
        }
        parent.changeSpec(setting, setting.getEventType().getFlag());
        return true;
    }

    @Override
    public boolean isMatch(ChampionRaceTimerTask.Setting setting) {
        return setting.getEventType() == TRIAL_GROUP
                || setting.getEventType() == KO_GROUP
                || setting.getEventType() == FINAL_GROUP;
    }

    @Override
    public void run() {

    }

    private void runFinalGroupWith(ChampionRaceTimerTask.Setting setting) {
        List<ChampionRacePs> sortedPs = parent.getSortedPs(
                Comparator.comparing(ChampionRacePs::getOpponent, Comparator.comparing(ChampionRaceOpponent::getWinCount, Comparator.reverseOrder()))
                        .thenComparing(ChampionRacePs::getOpponent, Comparator.comparing(ChampionRaceOpponent::getPoints, Comparator.reverseOrder())));
        List<String> finalPs = sortedPs.stream()
                .limit(8)
                .map(ChampionRacePs::getUid)
                .collect(Collectors.toList());
        int size = finalPs.size();
        for (int i = 0; i < Math.min(4, size); i++) {
            String uidA = finalPs.get(i);
            String uidB = (i + 4) <= (size - 1) ? finalPs.get(i + 4) : null;
            if (StringUtils.hasLength(uidA) || StringUtils.hasLength(uidB)) {
                ChampionRaceSpec spec = ChampionRaceSpec.ofFinal(
                        setting.getSpec().getSeason(),
                        (byte) 1);
                ChampionRaceRecord record = ChampionRaceRecord.of(
                        spec,
                        StringUtils.hasLength(uidA) ? uidA : null,
                        StringUtils.hasLength(uidB) ? uidB : null);
                record.setIndex((byte) i);
                parent.addRecordData(record);
            }
        }
    }

    private void runKoGroupWith(ChampionRaceTimerTask.Setting setting) {
        List<ChampionRacePs> sortedPs = parent.getSortedPs(
                Comparator.comparing(ChampionRacePs::getOpponent, Comparator.comparing(ChampionRaceOpponent::getWinCount, Comparator.reverseOrder()))
                        .thenComparing(ChampionRacePs::getOpponent, Comparator.comparing(ChampionRaceOpponent::getPoints, Comparator.reverseOrder())));
        List<ChampionRacePs> psList = sortedPs.stream()
                .limit(64)
                .collect(Collectors.toList());
        Map<Integer, List<ChampionRacePs>> groupList = Maps.newHashMap();

        int c = 0;
        for (ChampionRacePs ps : psList) {
            c = c % 8;
            groupList.computeIfAbsent(c, s -> Lists.newArrayList()).add(ps);
            c++;
        }
        for (Map.Entry<Integer, List<ChampionRacePs>> entry : groupList.entrySet()) {
            int group = entry.getKey();
            List<ChampionRacePs> gps = entry.getValue();
            gps.sort(Comparator.comparing(ChampionRacePs::getOpponent, Comparator.comparing(ChampionRaceOpponent::getWinCount, Comparator.reverseOrder()))
                    .thenComparing(ChampionRacePs::getOpponent, Comparator.comparing(ChampionRaceOpponent::getPoints, Comparator.reverseOrder())));
            int size = gps.size();

            for (int i = 0; i < Math.min(4, size); i++) {
                String uidA = gps.get(i).getUid();
                String uidB = (i + 4) <= (size - 1) ? gps.get(i + 4).getUid() : null;
                if (StringUtils.hasLength(uidA) || StringUtils.hasLength(uidB)) {
                    ChampionRaceSpec spec = ChampionRaceSpec.ofKo(
                            setting.getSpec().getSeason(),
                            (byte) group,
                            (byte) 1);
                    ChampionRaceRecord record = ChampionRaceRecord.of(
                            spec,
                            StringUtils.hasLength(uidA) ? uidA : null,
                            StringUtils.hasLength(uidB) ? uidB : null
                    );
                    record.setIndex((byte) i);
                    parent.addRecordData(record);
                }
            }
        }
    }

    private void runTrialGroupWith(ChampionRaceTimerTask.Setting setting) {
        List<ChampionRacePs> sortedPs = parent.getSortedPs(
                Comparator.comparing(ChampionRacePs::getOpponent, Comparator.comparing(opp -> -opp.getSnapshot().base.power)));
        int size = sortedPs.size();
        if (size == 1) {
            for (int i = 0; i < 6; i++) {
                ChampionRacePs psA = sortedPs.get(0);
                ChampionRaceSpec spec = ChampionRaceSpec.ofTrial(setting.getSpec().getSeason(), (byte) (i + 1));
                ChampionRaceRecord record = ChampionRaceRecord.of(spec, psA.getUid(), null);
                parent.addRecordData(record);
            }
        } else if (size <= 6) {
            for (ChampionRacePs epsA : sortedPs) {
                List<ChampionRacePs> oppList = sortedPs.stream()
                        .filter(eps -> eps != epsA)
                        .collect(Collectors.toList());
                for (int j = 0; j < 6; j++) {
                    ChampionRacePs epsB = oppList.get(Math.min(oppList.size() - 1, j));
                    ChampionRaceSpec spec = ChampionRaceSpec.ofTrial(setting.getSpec().getSeason(), (byte) (j + 1));
                    ChampionRaceRecord record = ChampionRaceRecord.of(spec, epsA.getUid(), epsB.getUid());
                    parent.addRecordData(record);
                }
            }
        } else {
            Random random = new Random();
            int szg = size / 6;
            for (int aidx = 0; aidx < size; ++ aidx) {
                for (int i = 0; i < 6; i++) {
                    int tempSzg = szg;
                    int szb = szg * (6 - i) - 1;
                    if (i == 0 && size % 6 > 0) {
                        szb += size % 6;
                        tempSzg += size % 6;
                    }
                    int bidx = szb - random.nextInt(tempSzg);
                    if (aidx == bidx) {
                        if (bidx == size - 1) {
                            bidx -= 1;
                        } else {
                            bidx += 1;
                        }
                    }
                    ChampionRacePs psA = sortedPs.get(aidx);
                    ChampionRacePs psB = sortedPs.get(bidx);
                    if (aidx == bidx || org.apache.commons.lang3.StringUtils.equals(psA.getUid(), psB.getUid())) {
                        log.info("怎么有一样的呢,aidx={},bidx={}, uid={}", aidx, bidx, psA.getUid());
                    }
                    ChampionRaceSpec spec = ChampionRaceSpec.ofTrial(setting.getSpec().getSeason(), (byte) (i + 1));
                    ChampionRaceRecord record = ChampionRaceRecord.of(spec, psA.getUid(), psB.getUid());
                    parent.addRecordData(record);
                }
            }
        }
    }
}
